package com.njcb.ams.support.beanprocessor;

import com.njcb.ams.store.stable.TradeConsoleService;
import com.njcb.ams.support.annotation.*;
import com.njcb.ams.support.config.AmsConfigUtil;
import com.njcb.ams.support.exception.ExceptionUtil;
import com.njcb.ams.support.trade.TradeService;
import com.njcb.ams.support.trade.bean.TradeServiceBean;
import com.njcb.ams.support.trade.filter.TradeLayerFilter;
import com.njcb.ams.util.AmsUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Component;

import javax.jws.WebService;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * spring bean初始化时,处理平台标记的服务类
 * 此类注解均集成@Component注解，受spring容器管理
 *
 * @author liuyanlong
 */
@Component
public class AmsBusinessBeanProcessor implements BeanPostProcessor, PriorityOrdered {
    private static final Logger logger = LoggerFactory.getLogger(AmsBusinessBeanProcessor.class);
    private static Map<String, String> map = new HashMap<String, String>();

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Interaction interaction = bean.getClass().getAnnotation(Interaction.class);
        if (null != interaction) {
            interactionExecute(bean, beanName, interaction);
        }

        //挡板代理服务处理
        if (null != bean.getClass().getAnnotation(HandleService.class)) {
            handleServiceExecute(bean, beanName);
        }

        if (null != bean.getClass().getAnnotation(TradeFilter.class)) {
            tradeFilterExecute(bean, beanName);
        }

        if (null != bean.getClass().getAnnotation(AmsConfig.class)) {
            amsConfigExecute(bean, beanName);
        }

        if (null != bean.getClass().getAnnotation(AmsConfigDefault.class)) {
            amsConfigDefaultExecute(bean, beanName);
        }

        /**
         * 处理插件的自定义注解
         */
        AmsConfigUtil.getScanAnnotations().forEach((cls, plug) -> {
            Annotation annotation = bean.getClass().getAnnotation(cls);
            if (null != annotation) {
                plug.annotationBean(bean, annotation);
            }
        });

        if (null != bean.getClass().getAnnotation(WebService.class)) {
            logger.info("webservice服务端实现类：" + bean.getClass().getName());
        }

        return bean;
    }

    /**
     * 处理添加了AmsConfig注解的类，将该类的父类和接口与该bean的对于管理起来，达到可以通过父类或接口查找到此bean的目的。
     *
     * @param bean
     * @param beanName
     */
    private void amsConfigExecute(Object bean, String beanName) {
        Class<?> superclass = bean.getClass().getSuperclass();
        if (!(superclass instanceof Object)) {
            AmsConfigUtil.addAmsConfigBean(superclass.getName(), bean);
        }
        Class<?>[] clsArr = bean.getClass().getInterfaces();
        for (Class<?> cls : clsArr) {
            AmsConfigUtil.addAmsConfigBean(cls.getName(), bean);
        }
    }

    private void amsConfigDefaultExecute(Object bean, String beanName) {
        Class<?> superclass = bean.getClass().getSuperclass();
        if (!(superclass instanceof Object)) {
            AmsConfigUtil.addAmsConfigDefaultBean(superclass.getName(), bean);
        }
        Class<?>[] clsArr = bean.getClass().getInterfaces();
        for (Class<?> cls : clsArr) {
            AmsConfigUtil.addAmsConfigDefaultBean(cls.getName(), bean);
        }
    }

    private void tradeFilterExecute(Object bean, String beanName) {
        if (!TradeLayerFilter.class.isAssignableFrom(bean.getClass())) {
            ExceptionUtil.throwAppException("被" + TradeFilter.class.getSimpleName() + "注解的类必须实现" + TradeLayerFilter.class.getSimpleName() + "接口");
        }
        TradeService.addTradeFilter((TradeLayerFilter) bean);
    }

    private void handleServiceExecute(Object bean, String beanName) {
        Method[] methods = bean.getClass().getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];
            Trader trader = method.getAnnotation(Trader.class);
            if (null == trader) {
                continue;
            }
            TradeServiceBean tradeBean = new TradeServiceBean();
            tradeBean.setBeanName(beanName);
            tradeBean.setMethod(method);
            tradeBean.setTradeCode(trader.tradeCode());
            tradeBean.setTrader(trader);
            TradeService.addTradeHandle(tradeBean);
        }
    }

    private void interactionExecute(Object bean, String beanName, Interaction interaction) {
        String groupName = interaction.groupName();
        if (AmsUtils.isNull(groupName) && null != bean.getClass().getAnnotation(TraderGroup.class)) {
            groupName = bean.getClass().getAnnotation(TraderGroup.class).groupName();
        }

        Method[] methods = bean.getClass().getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];
            if (null != method.getAnnotation(Uncheck.class)) {
                continue;
            }
            Trader trader = method.getAnnotation(Trader.class);
            String methodName = method.getName();
            if (null == trader) {
                logger.error("\n 实例化对象 [{}]时发生错误,函数[{}]必须添加Trader注解", beanName, methodName);
                System.exit(0);
            }
            if (map.containsKey(trader.tradeCode())) {
                if (!methodName.equals(map.get(trader.tradeCode()))) {
                    logger.error("\n 实例化对象[{}]时发生错误,函数[{}]与[{}]定义的交易码重复", beanName, map.get(trader.tradeCode()), methodName);
                    System.exit(0);
                }
            }
            map.put(trader.tradeCode(), methodName);
            TradeServiceBean tradeBean = new TradeServiceBean();
            tradeBean.setBeanName(beanName);
            tradeBean.setMethod(method);
            tradeBean.setMethodName(methodName);
            tradeBean.setTradeCode(trader.tradeCode());
            tradeBean.setTradeName(trader.tradeName());
            tradeBean.setTradeGroup(trader.tradeGroup());
            if (AmsUtils.isNull(tradeBean.getTradeGroup()) && AmsUtils.isNotNull(groupName)) {
                tradeBean.setTradeGroup(groupName);
            }
            tradeBean.setTrader(trader);
            TradeService.addTrade(tradeBean);
            TradeConsoleService.initStableMap(trader);
        }
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
